#include "study_v1.h"

#include <iostream>
#include <algorithm>


study_v1::study_v1()
{
}

study_v1::~study_v1()
{
}

bool study_v1::start()
{
#if 0
  std::cout << "########### START STUDY ###########" << std::endl;
  double prev_error = psignal_study_forward->geterror();
  uint32_t cicle_count = 0;

  for(; cicle_count < study_cicle_count_max; cicle_count ++)
  {
    std::cout << "+++++++++ cicle ID: " << cicle_count << " ++++++++++++++++" << std::endl;
    error_after_study = study4OneCicle();
    if(error_after_study <= max_study_error)
      break;
/*
	if(error_after_study > prev_error)
	{ //rallback
      neuron neuron_tmp = pneuron[data4rollback.neuron_id];
      synapse syn = neuron_tmp.getSynapse(data4rollback.syn_id);
      syn.setWeight(data4rollback.w);
      pneuron[data4rollback.neuron_id].setSynapse(syn, data4rollback.syn_id);
	} else
	  prev_error = error_after_study;
*/
  std::cout << "Error after study: " << error_after_study << " max allowed error: "<< max_study_error <<std::endl;
  std::cout << "Study cicle count: " << cicle_count << " max allowed cicle count: "<< study_cicle_count_max << std::endl;
  }
  std::cout << "########### FINISH STUDY ###########" << std::endl;
#endif
  return true;
}

void study_v1::findNeuronMaxError(int &nid, int &sid)
{
   neuron neuron_tmp;
   double f_w;
   double max_err = 0.;
   double tmp_err;
   int     nid4err;
   int     sid4err;
   int     nid_count;
   int     syn_count;
   int     syn_count_max;
   int     signal_count_max = study_in_signal.size();

   for(nid_count = 0; nid_count < neuron_count_max; nid_count ++)
   {
   	 neuron_tmp = pneuron[nid_count];
   	 syn_count_max = neuron_tmp.getSynapseCount();
   	 for(syn_count = 0; syn_count < syn_count_max; syn_count++)
   	 {
       synapse syn = neuron_tmp.getSynapse(syn_count);
       f_w = syn.getWeight();
       tmp_err = 0;
       for(int icount = 0; icount < signal_count_max; icount ++)
       {
         tmp_err += std::max(syn.getFSignalStudy(icount), syn.getBSignalStudy(icount)) - std::min(syn.getFSignalStudy(icount), syn.getBSignalStudy(icount));
	   }
       if(max_err < tmp_err) {
       	if(data4rollback.neuron_id == nid_count &&
			data4rollback.syn_id == syn_count)
          continue;
         max_err = tmp_err;
         nid4err = nid_count;
         sid4err = syn_count;
       }
   	 }
   }
   nid = nid4err;
   sid = sid4err;
}

double study_v1::study4OneCicle()
{
#if 0
  int nid = NONE_NEURON_ID, sid = NONE_SYNAPSE_ID;
  double f_error_study_before, f_error_study_after;

  f_error_study_before = psignal_study_forward->geterror();

  findNeuronMaxError(nid, sid);

  if(nid == NONE_NEURON_ID || sid == NONE_SYNAPSE_ID)
  {
    std::cout << "!!!!!! Error study: " << "neuron ID = NONE_NEURON_ID" << " synapseid =  NONE_SYNAPSE_ID" <<std::endl;
    return 0.0;
  }

  correctNeuron(nid, sid);

  psignal_study_forward->send(null, 0);
  psignal_study_back->send(null, 0);

  f_error_study_after = psignal_study_forward->geterror();

  return f_error_study_after;
}

void study_v1::correctNeuron(int nid, int sid)
{
   neuron neuron_tmp = pneuron[nid];
   int signal_count_max = study_in_signal.size();
   int    signal_id;
   double f_w;
   double max_dif = 0.;
   double tmp_dif = 0.;
   double  sign = 1.0;
   double fsum = 0., bsum = 0.;
   double tmp_w = 0.;

   synapse syn = neuron_tmp.getSynapse(sid);
   f_w = syn.getWeight();

   for(int icount = 0; icount < signal_count_max; icount ++)
   {
   	  neuron_tmp.setStudyBufferIndex(icount);
   	  tmp_w =+ neuron_tmp.clac_back_synapse_w(sid);
      fsum += syn.getFSignalStudy(icount);
      bsum += syn.getBSignalStudy(icount);
   }

   tmp_w = tmp_w / (double)signal_count_max;
/*
   	 if(fsum > bsum)
   	 	sign = -1.0;
	 else
   	 	sign = 1.0;
*/
   	 if(tmp_w > f_w)
   	 	sign = 1.0;
	 else
   	 	sign = -1.0;
   f_w = f_w + sign*(f_w/2.0);

   data4rollback.neuron_id = nid;
   data4rollback.syn_id    = sid;
   data4rollback.w         = syn.getWeight();

std::cout << "Correct neuron id: " << nid << " synapse ID: " << sid<< " from w: " << syn.getWeight() << " to w: " << f_w <<std::endl;

   syn.setWeight(f_w);
   pneuron[nid].setSynapse(syn, sid);
#endif;
   return 0.0;
}

double study_v1::studyError()
{
  return error_after_study;
}
